package com.hfy.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.hfy.admin.mapper.AdminMapper;
import com.hfy.admin.service.AdminService;
import com.hfy.model.Bo.SendCaptchaMailBo;
import com.hfy.model.dto.admin.CaptchaDto;
import com.hfy.model.po.admin.AdminPo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import result.Result;
import utils.CheckUtils;

import javax.servlet.http.HttpSession;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static constants.RabbitConstants.COMMON_SEND_CAPTCHA_MAIL_DIRECT_EXCHANGE;
import static constants.RabbitConstants.COMMON_SEND_CAPTCHA_MAIL_KEY;
import static constants.RedisConstants.ADMIN_LOGIN_CAPTCHA_KEY;
import static constants.RedisConstants.ADMIN_LOGIN_TOKEN_KEY;

/**
 * @ author 韩
 * time: 2024/7/22 9:52
 */

@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, AdminPo> implements AdminService {

    @Autowired
    private Cache<String, Integer> cache;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private HttpSession session;
    @Override
    public Result generateCaptcha(String email) {
        if (StrUtil.isBlank(email)) {
            return Result.error("不能为空");
        }
        if (!CheckUtils.isEmail(email)) {
            return Result.error("必须是邮箱格式");
        }
        if (cache.get(email, key -> 0) > 3) return Result.error("不要过于频繁地请求验证码，请一分钟后再试");
        // 去一下空格
        email = email.trim();
        // 校验一下该账号存不存在于数据库里
        AdminPo one = getOne(new LambdaQueryWrapper<AdminPo>().eq(AdminPo::getEmail, email));
        if (one == null) {
            return Result.error("没有该管理员账号");
        }
        int randomNum = new Random().nextInt(1000000); // 生成0到999999之间的随机数
        String captcha = String.format("%06d", randomNum);
        // 存到redis里，只会保存5分钟
        redisTemplate.opsForValue().set(ADMIN_LOGIN_CAPTCHA_KEY + email, captcha, 5, TimeUnit.MINUTES);

        // 这里用rabbitMQ做一个解耦

        SendCaptchaMailBo mailBo = new SendCaptchaMailBo(email, captcha);

        rabbitTemplate.convertAndSend(COMMON_SEND_CAPTCHA_MAIL_DIRECT_EXCHANGE, COMMON_SEND_CAPTCHA_MAIL_KEY, JSON.toJSONString(mailBo));


        // 缓存 + 1
        cache.put(email, cache.get(email, key -> 0) + 1);
        return Result.ok();
    }

    @Override
    public Result verifyCaptcha(CaptchaDto dto) {
        // 1. 先校验参数
        if (BeanUtil.isEmpty(dto)) {
            return Result.error("参数不能为空");
        }
        // 一定不为空
        String captcha = dto.getCaptcha().trim();
        String email = dto.getEmail().trim();
        if (!CheckUtils.isEmail(email)) {
            return Result.error("必须是邮箱格式");
        }
        // 其实可以先检验一下有没有该账号，但没啥必要
        String redisCaptcha = redisTemplate.opsForValue().get(ADMIN_LOGIN_CAPTCHA_KEY + email);

        if (StrUtil.equals(captcha, redisCaptcha)) {
            // 如果这两个验证码相等，就是登录成功了
            // 然后生成一个token
            String uuid = UUID.randomUUID().toString();
            String token = ADMIN_LOGIN_TOKEN_KEY + uuid;
            AdminPo adminPo = getOne(new LambdaQueryWrapper<AdminPo>().eq(AdminPo::getEmail, email));
//            redisTemplate.opsForHash().put(token, "id", adminPo.getId());
            redisTemplate.opsForHash().put(token, "id",String.valueOf(adminPo.getId()));
            redisTemplate.opsForHash().put(token, "email", adminPo.getEmail());
            redisTemplate.opsForHash().put(token, "roleType", String.valueOf(adminPo.getRoleType()));
            redisTemplate.opsForHash().put(token, "isDie", String.valueOf(adminPo.getIsDie()));

            // 前端存储一个 email，请求时的email都在session里拿
            return Result.ok(uuid);
        } else {
            return Result.error("验证失败，请重新请求");
        }


    }
}
